package com.fowo.api.datainterface.util;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.db.sql.SqlUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.webservice.SoapRuntimeException;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONPath;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.fowo.api.common.query.SqlInjectionUtil;
import com.fowo.api.common.util.ContextHolder;
import com.fowo.api.datainterface.constants.MappingColFixedKind;
import com.fowo.api.datainterface.constants.RequestFieldTypeKind;
import com.fowo.api.datainterface.model.DataContextModel;
import com.fowo.api.datainterface.model.DataInterfaceModel;
import com.fowo.api.datainterface.entity.DatainterfaceAuthority;
import com.fowo.api.user.model.JwtUserInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPException;
import java.nio.charset.Charset;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.List;
import java.util.Map;

@Slf4j
@DS("ds24")
@Component
public class Common {
    //    @Resource
//    private SQLManager sqlManager;
    private JdbcTemplate jdbcTemplate;

    public JdbcTemplate getJdbcTemplate() {
        return ObjectUtil.isNotEmpty(jdbcTemplate) ? jdbcTemplate : new JdbcTemplate(ContextHolder.getApplicationContext().getBean(DataSource.class));
    }

    /**
     * 基准URL+相对URL
     *
     * @param rootPath
     * @param interfaceUrl
     * @return
     */
    public String convertRequestPath(String rootPath, String interfaceUrl) {
        try {
            interfaceUrl = StrUtil.trim(interfaceUrl);
            if (HttpUtil.isHttp(interfaceUrl) || HttpUtil.isHttps(interfaceUrl)) {
                return interfaceUrl;
            } else if (HttpUtil.isHttp(rootPath) || HttpUtil.isHttps(rootPath)) {
                return URLUtil.completeUrl(rootPath, interfaceUrl);
            } else {
                Assert.isTrue(false, "参数类型错误，指定的API路径错误！");
            }
        } catch (Exception ex) {
            Assert.isTrue(false, "URL路径配置错误，错误提示:" + ex.getMessage());
        }
        return null;
    }

    /**
     * 转换参数
     *
     * @param jsonToListMap
     * @return
     */
    public JSONObject convertCurrentMap(JSONObject currentParamsMap, List<JSONObject> jsonToListMap) {
        try {
            if (CollUtil.isNotEmpty(jsonToListMap)) {
                if (ObjectUtil.isEmpty(currentParamsMap)) {
                    currentParamsMap = new JSONObject();
                }
                for (JSONObject maps : jsonToListMap) {
                    convertDefaultValue(currentParamsMap, maps);
                }
            }
        } catch (Exception ex) {
            Assert.isTrue(false, "转换参数异常！错误提示:" + ex.getMessage());
        }
        return currentParamsMap;
    }


    /**
     * 处理URL参数
     *
     * @param currentParamsMap
     * @param path
     * @param requestParamsListMap 默认值
     * @return
     */
    public String processUrlArgs(JSONObject currentParamsMap, String path, List<JSONObject> requestParamsListMap) {
        try {
            path = StrUtil.concat(true, path, path.contains("?") ? "&" : "?");
            // 判断是否使用默认值
            if (MapUtil.isNotEmpty(currentParamsMap)) {
                for (String field : currentParamsMap.keySet()) {
                    String value = MapUtil.getStr(currentParamsMap, field, StrUtil.EMPTY);
                    path = path + field + "=" + value.replaceAll("'", "") + "&";
                }
            } else {
                if (CollUtil.isNotEmpty(requestParamsListMap)) {
                    for (JSONObject maps : requestParamsListMap) {
                        if (MapUtil.isNotEmpty(maps)) {
                            String field = MapUtil.getStr(maps, DataInterfaceModel.Fields.field);
                            String defaultValue = MapUtil.getStr(maps, DataInterfaceModel.Fields.defaultValue);
                            try {
                                defaultValue = HttpUtil.encodeParams(defaultValue, Charset.defaultCharset());
                                path = path + field + "=" + defaultValue + "&";
                            } catch (Exception e) {
                                Assert.isTrue(false, "HTTP调用GET请求参数拼装错误，错误提示:" + e.getMessage());
                            }
                        }
                    }
                }
            }
            path = StrUtil.removeSuffix(path, "&");

        } catch (Exception ex) {
            Assert.isTrue(false, "URL参数转换错误，错误提示:" + ex.getMessage());
        }
        return StrUtil.removeSuffix(path, "?");
    }


    /**
     * 处理Body参数
     *
     * @param currentParamsMap
     * @param jsonObject
     * @param requestParamsListMap 默认值
     */
    public JSONObject processBodyArgs(JSONObject currentParamsMap, JSONObject jsonObject, List<JSONObject> requestParamsListMap) {
        try {
            if (MapUtil.isEmpty(jsonObject)) {
                jsonObject = new JSONObject();
            }
            // 判断是否使用默认值
            if (MapUtil.isNotEmpty(currentParamsMap)) {
                for (String field : currentParamsMap.keySet()) {
                    Object value = MapUtil.get(currentParamsMap, field, Object.class);
                    jsonObject.put(field, value);
                }
            } else {
                if (CollUtil.isNotEmpty(requestParamsListMap)) {
                    for (JSONObject maps : requestParamsListMap) {
                        convertDefaultValue(currentParamsMap, maps);
                    }
                }
            }
        } catch (Exception ex) {
            Assert.isTrue(false, "Body参数转换错误，错误提示:" + ex.getMessage());
        }
        return jsonObject;
    }

    /**
     * 处理Header参数
     *
     * @param currentHeadersMap
     * @param headers
     * @param requestHeadersListMap
     */
    public HttpHeaders processHeaderArgs(JSONObject currentHeadersMap, HttpHeaders headers, List<JSONObject> requestHeadersListMap) {
        try {
            headers.setContentType(MediaType.parseMediaType(MediaType.APPLICATION_JSON_UTF8_VALUE));
            // 判断是否使用默认值
            if (MapUtil.isNotEmpty(currentHeadersMap)) {
                for (String field : currentHeadersMap.keySet()) {
                    String value = MapUtil.getStr(currentHeadersMap, field);
                    headers.set(field, value);
                }
            } else {
                if (CollUtil.isNotEmpty(requestHeadersListMap)) {
                    for (JSONObject maps : requestHeadersListMap) {
                        if (MapUtil.isNotEmpty(maps)) {
                            if (MapUtil.isNotEmpty(maps)) {
                                String field = MapUtil.getStr(maps, DataInterfaceModel.Fields.field);
                                String value = MapUtil.getStr(maps, DataInterfaceModel.Fields.defaultValue);
                                headers.set(field, value);
                            }
                        }
                    }
                }
            }
        } catch (
                Exception ex) {
            Assert.isTrue(false, "Header参数转换错误，错误提示:" + ex.getMessage());
        }
        return headers;
    }

    /**
     * 默认参数替换
     *
     * @param currentParamsMap
     * @param maps
     */
    private void convertDefaultValue(JSONObject currentParamsMap, JSONObject maps) {
        if (MapUtil.isNotEmpty(maps)) {
            String field = MapUtil.getStr(maps, DataInterfaceModel.Fields.field, StrUtil.EMPTY);
            String defaultValueStr = MapUtil.getStr(maps, DataInterfaceModel.Fields.defaultValue);
            if (StrUtil.isNotBlank(defaultValueStr)) {
                //过滤sql
                defaultValueStr = executeSql(defaultValueStr, null, MapUtil.getStr(maps, DataInterfaceModel.Fields.fieldType));
                //默认值替换&格式转换
                if (EnumUtil.getFieldValues(MappingColFixedKind.class, "value").contains(defaultValueStr)) {
                    currentParamsMap.put(field, convertColSysariables(defaultValueStr, defaultValueStr));
                } else if (StrUtil.equalsIgnoreCase(RequestFieldTypeKind.Int.getValue(), MapUtil.getStr(maps, DataInterfaceModel.Fields.fieldType)) ||
                        StrUtil.equalsIgnoreCase(RequestFieldTypeKind.Long.getValue(), MapUtil.getStr(maps, DataInterfaceModel.Fields.fieldType))) {
                    if (!currentParamsMap.containsKey(field)) {
                        currentParamsMap.put(field, Convert.toLong(defaultValueStr, null));
                    }
                } else if (StrUtil.equalsIgnoreCase(RequestFieldTypeKind.Decimal.getValue(), MapUtil.getStr(maps, DataInterfaceModel.Fields.fieldType)) ||
                        StrUtil.equalsIgnoreCase(RequestFieldTypeKind.Float.getValue(), MapUtil.getStr(maps, DataInterfaceModel.Fields.fieldType)) ||
                        StrUtil.equalsIgnoreCase(RequestFieldTypeKind.Double.getValue(), MapUtil.getStr(maps, DataInterfaceModel.Fields.fieldType))) {
                    if (!currentParamsMap.containsKey(field)) {
                        currentParamsMap.put(field, Convert.toDouble(defaultValueStr, null));
                    }
                } else if (StrUtil.equalsIgnoreCase(RequestFieldTypeKind.Array.getValue(), MapUtil.getStr(maps, DataInterfaceModel.Fields.fieldType))) {
                    if (!currentParamsMap.containsKey(field)) {
                        currentParamsMap.put(field, JsonUtil.getJsonToJsonArraySafe(defaultValueStr));
                    }
                } else if (StrUtil.equalsIgnoreCase(RequestFieldTypeKind.Object.getValue(), MapUtil.getStr(maps, DataInterfaceModel.Fields.fieldType))) {
                    if (!currentParamsMap.containsKey(field)) {
                        currentParamsMap.put(field, JsonUtil.getJsonToBeanSafe(defaultValueStr, JSONObject.class));
                    }
                } else if (StrUtil.equalsIgnoreCase(RequestFieldTypeKind.Null.getValue(), MapUtil.getStr(maps, DataInterfaceModel.Fields.fieldType))) {
                    if (!currentParamsMap.containsKey(field)) {
                        currentParamsMap.put(field, null);
                    }
                } else {
                    if (!currentParamsMap.containsKey(field)) {
                        currentParamsMap.put(field, defaultValueStr);
                    }
                }
            }
        }
    }

    /**
     * 执行sql：是sql：执行，不是：返回默认值
     *
     * @param value
     * @param param
     * @param fieldType
     * @return
     */
    public String executeSql(String value, Object param, String fieldType) {
        // 统一转为小写
        if (StrUtil.isNotBlank(value)) {
            String sql = value.toLowerCase();
            try {
                if (StrUtil.isNotBlank(sql) && StrUtil.containsAll(sql, "select") && StrUtil.contains(SqlUtil.formatSql(sql), StrUtil.C_LF)) {
                    if (ObjectUtil.isEmpty(param) && StrUtil.containsAll(sql, "where", "?")) {
                        return null;
                    } else if (ObjectUtil.isNotEmpty(param) && !StrUtil.containsAll(sql, "where", "?")) {
                        return null;
                    } else {
                        //防注入
                        SqlInjectionUtil.filterContent(sql);
                        //SQLReady sqlReady = ObjectUtil.isNotEmpty(param) && StrUtil.containsAll(sql, "where", "?") ? new SQLReady(sql, param) : new SQLReady(sql);
                        if (StrUtil.equalsIgnoreCase(RequestFieldTypeKind.Array.getValue(), fieldType)) {
                            //return JsonUtil.getObjectToString(sqlManager.execute(sqlReady, Map.class));
                            if (ObjectUtil.isEmpty(param)) {
                                return JsonUtil.getObjectToString(getJdbcTemplate().queryForList(sql));
                            }
                            return JsonUtil.getObjectToString(getJdbcTemplate().queryForList(sql, param));
                        } else if (StrUtil.equalsIgnoreCase(RequestFieldTypeKind.Object.getValue(), fieldType)) {
                            //return JsonUtil.getObjectToString(sqlManager.executeQueryOne(sqlReady, Map.class));
                            if (ObjectUtil.isEmpty(param)) {
                                return JsonUtil.getObjectToString(CollUtil.getFirst(getJdbcTemplate().queryForList(sql)));
                            }
                            return JsonUtil.getObjectToString(CollUtil.getFirst(getJdbcTemplate().queryForList(sql, param)));
                        } else {
                            //return sqlManager.executeQueryOne(sqlReady, String.class);
                            if (ObjectUtil.isEmpty(param)) {
                                return CollUtil.getFirst(getJdbcTemplate().queryForList(sql, String.class));
                            }
                            return CollUtil.getFirst(getJdbcTemplate().queryForList(sql, new Object[]{param}, String.class));
                        }
                    }

                }
            } catch (Exception ex) {
                Assert.isTrue(false, "执行sql异常 语句: {} 参数: {}，错误提示: {}", sql, param, ex.getMessage());
            }
        }
        return value;
    }

    /**
     * 转换请求类型
     *
     * @param requestMethod
     * @return
     */
    public HttpMethod convertRequestMethod(String requestMethod) {
        Validator.validateTrue(StrUtil.isNotEmpty(requestMethod), "参数类型错误，未指定请求参数！");
        return EnumUtil.likeValueOf(HttpMethod.class, requestMethod.toUpperCase());
    }

    /**
     * 计算执行时间
     *
     * @param dateTime
     * @return
     */
    public int invokTime(LocalDateTime dateTime) {
        //调用时间
        int invokWasteTime = Integer.valueOf((int) (System.currentTimeMillis() - dateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli()));
        return invokWasteTime;
    }


    /**
     * 转换默认值
     *
     * @param value
     * @param colSysariables
     * @return
     */
    public Object convertColSysariables(String value, String colSysariables) {
        JwtUserInfo jwtUserInfo = JwtUserInfo.fromHeader();
        if (ObjectUtil.isEmpty(jwtUserInfo)) {
            jwtUserInfo = new JwtUserInfo();
        }
        if (StrUtil.contains(colSysariables, MappingColFixedKind.UserName.getValue())) {
            return StrUtil.emptyToDefault(StrUtil.toStringOrNull(jwtUserInfo.getUserId()), "1");
        } else if (StrUtil.contains(colSysariables, MappingColFixedKind.Name.getValue())) {
            return StrUtil.emptyToDefault(jwtUserInfo.getUsername(), "管理员");
        } else if (StrUtil.contains(colSysariables, MappingColFixedKind.CurDate.getValue())) {
            return DateUtil.format(DateUtil.date(), DatePattern.NORM_DATE_PATTERN);
        } else if (StrUtil.contains(colSysariables, MappingColFixedKind.CurTime.getValue())) {
            return DateUtil.format(DateUtil.date(), DatePattern.NORM_TIME_PATTERN);
        } else if (StrUtil.contains(colSysariables, MappingColFixedKind.Now.getValue())) {
            return DateUtil.format(DateUtil.date(), DatePattern.NORM_DATETIME_PATTERN);
        } else if (StrUtil.contains(colSysariables, MappingColFixedKind.PK.getValue())) {
            return IdWorker.getId();
        } else if (StrUtil.contains(colSysariables, MappingColFixedKind.TimeStampMS.getValue())) {
            return DateUtil.current();
        } else if (StrUtil.contains(colSysariables, MappingColFixedKind.TimeStampS.getValue())) {
            return DateUtil.currentSeconds();
        } else if (StrUtil.contains(colSysariables, MappingColFixedKind.StartTimeStampMS.getValue())) {
            return DateUtil.beginOfDay(DateUtil.date()).getTime();
        } else if (StrUtil.contains(colSysariables, MappingColFixedKind.StartTimeStampS.getValue())) {
            return DateUtil.beginOfDay(DateUtil.date()).getTime() / 1000;
        }
        return value;
    }


    /**
     * 打包成功数据
     *
     * @param to
     * @param successDataList
     */
    public void packSuccessData(DataContextModel.DatainterfaceToModel to, List<JSONObject> successDataList) {
        if (CollUtil.isNotEmpty(successDataList)) {
            to.setMappingSuccessData(MapUtil.of(to.getEnCode(), successDataList));
        }
    }

    /**
     * 打包失败数据
     *
     * @param to
     * @param failDataList
     */
    public void packFailData(DataContextModel.DatainterfaceToModel to, List<JSONObject> failDataList) {
        if (CollUtil.isNotEmpty(failDataList)) {
            to.setMappingFailData(MapUtil.of(to.getEnCode(), failDataList));
        }
    }


    /**
     * 获取权限信息
     *
     * @param authority
     * @param key
     * @return
     */
    public static String getAuthoritySimpleFactory(DatainterfaceAuthority authority, String key) {
        if (ObjectUtil.isEmpty(authority) || StrUtil.isBlank(key)) {
            Assert.isTrue(false, "授权信息{}不存在！", key);
        }
        JSONArray appAuthInfo = JsonUtil.getJsonToJsonArray(authority.getAppAuthInfo());
        if (ObjectUtil.isEmpty(appAuthInfo)) {
            Assert.isTrue(false, "授权信息{}不存在！", key);
        }
        try {
            return StrUtil.toStringOrNull(JSONPath.eval(appAuthInfo, StrUtil.format("['{}'][0]", key), true));
        } catch (Exception ex) {
            Assert.isTrue(false, "授权信息{}不存在！", key);
        }
        return null;
    }

    public static boolean isEmpty(Object object) {
        if (object == null) {
            return (true);
        }
        if ("".equals(object)) {
            return (true);
        }
        if (StrUtil.NULL.equals(object)) {
            return (true);
        }
        return (false);
    }

    public static boolean isNotEmpty(Object object) {
        if (object != null && !"".equals(object) && !object.equals(StrUtil.NULL)) {
            return (true);
        }
        return (false);
    }


    /**
     * 设置方法参数
     *
     * @param ele    方法节点
     * @param name   参数名
     * @param value  参数值
     * @param prefix 命名空间前缀， {@code null}表示不使用前缀
     * @return {@link SOAPElement}子节点
     */
    @SuppressWarnings("rawtypes")
    public static SOAPElement setParam(SOAPElement ele, String name, Object value, String prefix) {
        final SOAPElement childEle;
        try {
            if (StrUtil.isNotBlank(prefix)) {
                childEle = ele.addChildElement(name, prefix);
            } else {
                childEle = ele.addChildElement(name);
            }
        } catch (SOAPException e) {
            throw new SoapRuntimeException(e);
        }

        if (null != value) {
            if (value instanceof SOAPElement) {
                // 单个子节点
                try {
                    ele.addChildElement((SOAPElement) value);
                } catch (SOAPException e) {
                    throw new SoapRuntimeException(e);
                }
            } else if (value instanceof Map) {
                // 多个字节点
                Map.Entry entry;
                for (Object obj : ((Map) value).entrySet()) {
                    entry = (Map.Entry) obj;
                    setParam(childEle, entry.getKey().toString(), entry.getValue(), prefix);
                }
            } else if (value instanceof List) {
                // 多个字节点
                for (Object objList : (List) value) {
                    if (objList instanceof Map) {
                        Map.Entry entry;
                        for (Object obj : ((Map) objList).entrySet()) {
                            entry = (Map.Entry) obj;
                            setParam(childEle, entry.getKey().toString(), entry.getValue(), prefix);
                        }
                    }
                }
            } else {
                // 单个值
                childEle.setValue(value.toString());
            }
        }

        return childEle;
    }

}
